package com.yirui.serialcomm.client;

import com.yirui.serialcomm.core.Connector;
import com.yirui.serialcomm.core.MCChunkIterator;
import com.yirui.serialcomm.core.domain.SerialCommPacket;
import com.yirui.serialcomm.core.domain.StreamType;
import com.yirui.serialcomm.core.parse.MCPacketParser;
import com.yirui.serialcomm.core.parse.PacketParser;
import com.yirui.serialcomm.core.protocol.SerialCommServer;
import com.yirui.serialcomm.core.protocol.TcpBridgeServer;
import com.yirui.serialcomm.core.protocol.UdpBridgeServer;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.io.PipedInputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 启动网络端口数据打包后转串口通道传输
 * @author Dujie
 * @create 2025/8/5
 * @since 1.0.0
 */
@Component
@Slf4j
public class NetworkToSerialComm {

    private int tcpPort;
    private int udpPort;
    private String serialComm;
    private TcpBridgeServer tcpServer;
    private UdpBridgeServer udpServer;
    private SerialCommServer serialCommServer;
    private ExecutorService executorService;
    private final AtomicBoolean runState = new AtomicBoolean(true);
    private PacketParser packetParser = new MCPacketParser();
    public void start(int tcpPort, int udpPort, String serialComm) throws Exception {
        runState.set(true);
        this.tcpPort = tcpPort;
        this.udpPort = udpPort;
        this.serialComm = serialComm;
        if(executorService == null || executorService.isShutdown()){
            executorService = Executors.newSingleThreadExecutor();
        }

        //启动tcp服务
        tcpServer = new TcpBridgeServer(tcpPort);
        tcpServer.setPacketParser(this.packetParser);

        //启动upd服务
        udpServer = new UdpBridgeServer(udpPort);
        udpServer.setPacketParser(this.packetParser);
        //启动串口服务
        serialCommServer = new SerialCommServer(serialComm);

        //连接处理
        Connector fullDuplexConnector = new Connector(); //tcp/udp公用管道连接器

        tcpServer.setConnector(fullDuplexConnector);

        udpServer.setConnector(fullDuplexConnector);

        Connector serialCommConnector = new Connector();//串口专属管道连接器
        serialCommServer.setConnector(serialCommConnector);
        //创建连接
        serialCommConnector.connectTo(fullDuplexConnector);
        fullDuplexConnector.connectTo(serialCommConnector);

        //启动
        tcpServer.start();
        udpServer.start();
        serialCommServer.start();

        startCommToNetWriteDataThread(fullDuplexConnector.getPipedInputStream(), serialCommServer.getMaxBufferSize());

    }

    public void setPacketParser(PacketParser packetParser) {
        this.packetParser = packetParser;
    }


    /**
     * 获取COMM应答数据包类型转发给不同的Net通道
     * @param pipedInputStream
     * @param maxBufferSize
     */
    private void startCommToNetWriteDataThread(PipedInputStream pipedInputStream,  int maxBufferSize){
        executorService.submit(()->{
            log.info("[启动] 从串口管道:{}获取数据转发到Net客户端:[{}/TCP {}/UDP].",serialComm, tcpPort, udpPort);
            SerialCommPacket packet;
            MCChunkIterator<SerialCommPacket> iterator = new MCChunkIterator(pipedInputStream, packetParser);

            //收集断包数据
            while (runState.get()) {
                try {
                    if(iterator.hasNext()){
                        packet = iterator.next();

                        if(packet.getType() == StreamType.TCP){
                            tcpServer.send(Unpooled.copiedBuffer(packet.getData(), 0, packet.getData().length));
                        }else{
                            udpServer.send(Unpooled.copiedBuffer(packet.getData(), 0, packet.getData().length));
                        }
                    }


                } catch (Exception ex) {
                    log.error("从Net管道读取数据向Net客户端发生应答数据异常:{}", ex);
                }
            }

        });
    }

    @PreDestroy
    public void stop(){
        runState.set(false);
        if(tcpServer != null){
            tcpServer.stop();
            tcpServer = null;
        }
        if(udpServer != null){
            udpServer.stop();
            udpServer = null;
        }
        if(serialCommServer != null){
            serialCommServer.stop();
           // serialCommServer = null;
        }
        if(executorService != null){
            executorService.shutdown();
        }
    }

    @Override
    public String toString() {
        return "NetworkToSerialComm{" +
                "tcpPort=" + tcpPort +
                ", udpPort=" + udpPort +
                ", serialComm='" + serialComm + '\'' +
                ", writeUpdateTime="+serialCommServer.getWriteTime()+
                ", readUpdateTime="+serialCommServer.getReadTime()+
                '}';
    }
}
